package cn.wjssl.infrastructure.persistent.repository;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import cn.wjssl.domain.rebate.model.aggregate.BehaviorRebateAggregate;
import cn.wjssl.domain.rebate.model.entity.BehaviorRebateOrderEntity;
import cn.wjssl.domain.rebate.model.entity.TaskEntity;
import cn.wjssl.domain.rebate.model.valobj.BehaviorTypeVO;
import cn.wjssl.domain.rebate.model.valobj.DailyBehaviorRebateVO;
import cn.wjssl.domain.rebate.repository.IBehaviorRebateRepository;
import cn.wjssl.infrastructure.event.EventPublisher;
import cn.wjssl.infrastructure.persistent.dao.IDailyBehaviorRebateDao;
import cn.wjssl.infrastructure.persistent.dao.ITaskDao;
import cn.wjssl.infrastructure.persistent.dao.IUserBehaviorRebateOrderDao;
import cn.wjssl.infrastructure.persistent.po.DailyBehaviorRebatePO;
import cn.wjssl.infrastructure.persistent.po.TaskPO;
import cn.wjssl.infrastructure.persistent.po.UserBehaviorRebateOrderPO;
import cn.wjssl.types.enums.ResponseCode;
import cn.wjssl.types.exception.AppException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 用户行为返利仓储
 */
@Slf4j
@Repository
public class BehaviorRebateRepository implements IBehaviorRebateRepository {

    @Resource
    private IDailyBehaviorRebateDao dailyBehaviorRebateDao;
    @Resource
    private IUserBehaviorRebateOrderDao rebateOrderDao;
    @Resource
    private ITaskDao taskDao;
    @Resource
    private IDBRouterStrategy dbRouter;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private EventPublisher eventPublisher;

    // 根据用户行为类型, 查询返利配置
    @Override
    public List<DailyBehaviorRebateVO> queryDailyBehaviorRebateConfig(BehaviorTypeVO behaviorTypeVO) {
        List<DailyBehaviorRebatePO> dailyBehaviorRebatePOS = dailyBehaviorRebateDao.queryDailyBehaviorRebateByBehaviorType(behaviorTypeVO.getCode());
        List<DailyBehaviorRebateVO> behaviorRebateVOS = new ArrayList<>(dailyBehaviorRebatePOS.size());
        for (DailyBehaviorRebatePO dailyBehaviorRebatePO : dailyBehaviorRebatePOS) {
            behaviorRebateVOS.add(DailyBehaviorRebateVO.builder()
                    .behaviorType(dailyBehaviorRebatePO.getBehaviorType())
                    .rebateDesc(dailyBehaviorRebatePO.getRebateDesc())
                    .rebateType(dailyBehaviorRebatePO.getRebateType())
                    .rebateConfig(dailyBehaviorRebatePO.getRebateConfig())
                    .build()
            );
        }
        return behaviorRebateVOS;
    }

    // 事务存入用户行为订单, task任务, 发送mq消息
    @Override
    public void saveUserRebateRecord(String userId, List<BehaviorRebateAggregate> behaviorRebateAggregates) {

        // 事务入库
        try {
            // 设置路由
            dbRouter.doRouter(userId);
            // 事务存入order表, task表
            transactionTemplate.execute(status -> {
                try {
                    // 遍历聚合对象列表, 存入order表, task表
                    for (BehaviorRebateAggregate aggregate : behaviorRebateAggregates) {
                        // 存入order表
                        BehaviorRebateOrderEntity behaviorRebateOrderEntity = aggregate.getBehaviorRebateOrderEntity();
                        UserBehaviorRebateOrderPO orderPO = new UserBehaviorRebateOrderPO();
                        orderPO.setUserId(userId);
                        orderPO.setOrderId(behaviorRebateOrderEntity.getOrderId());
                        orderPO.setBehaviorType(behaviorRebateOrderEntity.getBehaviorType());
                        orderPO.setRebateDesc(behaviorRebateOrderEntity.getRebateDesc());
                        orderPO.setRebateType(behaviorRebateOrderEntity.getRebateType());
                        orderPO.setRebateConfig(behaviorRebateOrderEntity.getRebateConfig());
                        orderPO.setOutBusinessNo(behaviorRebateOrderEntity.getOutBusinessNo());
                        orderPO.setBizId(behaviorRebateOrderEntity.getBizId());
                        rebateOrderDao.insert(orderPO);

                        // 存入task表
                        TaskEntity taskEntity = aggregate.getTaskEntity();
                        TaskPO taskPO = new TaskPO();
                        taskPO.setUserId(userId);
                        taskPO.setTopic(taskEntity.getTopic());
                        taskPO.setMessageId(taskEntity.getMessageId());
                        taskPO.setMessage(JSON.toJSONString(taskEntity.getMessage()));
                        taskPO.setState(taskEntity.getState().getCode());
                        taskDao.insert(taskPO);
                    }
                    return 1;
                } catch (DuplicateKeyException e) {
                    status.setRollbackOnly();
                    log.error("写入返利记录，唯一索引冲突 userId: {}", userId, e);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(), e);
                }
            });
        } finally {
            dbRouter.clear();
        }

        // 发送mq消息
        for (BehaviorRebateAggregate aggregate : behaviorRebateAggregates) {
            TaskEntity taskEntity = aggregate.getTaskEntity();
            // 用于更新task状态
            TaskPO taskPO = new TaskPO();
            taskPO.setUserId(taskEntity.getUserId());
            taskPO.setMessageId(taskEntity.getMessageId());
            try {
                // 发送消息
                eventPublisher.publish(taskEntity.getTopic(), taskEntity.getMessage());
                // 发送成功, 更新状态为complete
                taskDao.updateTaskSendMessageCompleted(taskPO);
            } catch (Exception e) {
                log.error("写入返利记录，发送MQ消息失败 userId: {} topic: {}", userId, taskPO.getTopic());
                // 发送失败
                taskDao.updateTaskSendMessageFail(taskPO);
            }
        }
    }

    // 根据userId, outBusinessNo 查询 RebateOrderEntity 列表
    @Override
    public List<BehaviorRebateOrderEntity> queryOrderByOutBusinessNo(String userId, String outBusinessNo) {
        UserBehaviorRebateOrderPO orderPO = new UserBehaviorRebateOrderPO();
        orderPO.setUserId(userId);
        orderPO.setOutBusinessNo(outBusinessNo);
        List<UserBehaviorRebateOrderPO> orderPOS = rebateOrderDao.queryOrderByOutBusinessNo(orderPO);
        List<BehaviorRebateOrderEntity> resList = new ArrayList<>(orderPOS.size());
        for (UserBehaviorRebateOrderPO PO : orderPOS) {
            resList.add(BehaviorRebateOrderEntity.builder()
                    .userId(PO.getUserId())
                    .orderId(PO.getOrderId())
                    .behaviorType(PO.getBehaviorType())
                    .rebateDesc(PO.getRebateDesc())
                    .rebateType(PO.getRebateType())
                    .rebateConfig(PO.getRebateConfig())
                    .outBusinessNo(PO.getOutBusinessNo())
                    .bizId(PO.getBizId())
                    .build()
            );
        }
        return resList;
    }


}
